<script lang="ts">
import { useTimestamp } from '@peng_kai/kit/libs/vueuse';

export interface CountdownProps {
  value?: number | ReturnType<typeof dayjs> | Date;
  hiddenTopText?: boolean; // 隐藏顶部文字
  hiddenFlicker?: boolean; // 隐藏间隔的闪烁动效
  topTextClassName?: string;
  itemClassName?: string;
  onFinish?: () => void;
};

export const padZero = (num: number) => num < 10 ? `0${num}` : `${num}`;

export function formatText(num: number, suffix = '', isPadZero = true) {
  const prefix = isPadZero ? padZero(num) : String(num);
  return `${prefix}${suffix}`;
}

export type DiffInfoKeysType = 'd' | 'h' | 'm' | 's';
export type DiffInfoType = Record<DiffInfoKeysType, number>;

const diffInfoKeys: DiffInfoKeysType[] = ['d', 'h', 'm', 's'];
const topTextMap: Record<DiffInfoKeysType, string> = { d: 'Day', h: 'Hour', m: 'Min', s: 'Sec' };

export interface SlotProps { diff: DiffInfoType; padZero: typeof padZero; formatText: typeof formatText };
export interface ItemInfoType { topText: string; timeText: string; type: DiffInfoKeysType }
</script>

<script lang="ts" setup>
const props = defineProps<CountdownProps>();

const slots = defineSlots<{ default?: (data: SlotProps) => any }>();

const { timestamp: currentTime, pause } = useTimestamp({ controls: true, interval: 200 });

const getDateInfoRef = computed(() => {
  const { value } = props;
  const currentDate = dayjs(currentTime.value);
  const valueD = typeof value === 'number' ? dayjs(value > 0 ? value : 'kkkkk') : dayjs(value);
  const valueDate = valueD?.isValid() && valueD?.isAfter(currentDate) ? valueD : currentDate;
  return { currentDate, valueDate };
});

const getDiffInfoRef = computed((): DiffInfoType => {
  const { currentDate, valueDate } = getDateInfoRef.value;
  const diff = dayjs.duration(valueDate.diff(currentDate));
  return { d: Math.floor(diff.asDays()), h: diff.hours(), m: diff.minutes(), s: diff.seconds() };
});

const getIsFinishRef = computed(() => diffInfoKeys.map(k => getDiffInfoRef.value[k]).every(x => x <= 0));

watch(getIsFinishRef, (v) => {
  v && props.onFinish?.();
  v && pause();
}, { immediate: true });

const getInfoListRef = computed((): [ItemInfoType, ItemInfoType] => {
  const { d: dv, h: hv, m: mv, s: sv } = getDiffInfoRef.value;
  const hVal = (dv * 24) + hv;
  const hInfo: ItemInfoType = { topText: topTextMap.h, timeText: padZero(hVal), type: 'h' };
  const mInfo: ItemInfoType = { topText: topTextMap.m, timeText: padZero(mv), type: 'm' };
  const sInfo: ItemInfoType = { topText: topTextMap.s, timeText: padZero(sv), type: 's' };
  return hVal > 0 ? [hInfo, mInfo] : [mInfo, sInfo];
});
</script>

<template>
  <div v-if="slots.default" class="text-sm">
    <slot :diff="getDiffInfoRef" :padZero="padZero" :formatText="formatText" />
  </div>
  <div v-else class="flex shrink-0 items-center text-sm">
    <template v-for="(item, idx) of getInfoListRef" :key="idx">
      <div class="relative flex-center shrink-0" :class="itemClassName || 'rounded-1 bg-white/50 px-[9px] py-[7px]'">
        <div v-if="!hiddenTopText" class="absolute -transform-translate-y-full" :class="topTextClassName || 'text-xs -top-0.5'">
          {{ item.topText }}
        </div>
        <div>{{ item.timeText }}</div>
      </div>
      <div
        v-if="idx + 1 < getInfoListRef.length"
        class="mx-1 block font-semibold"
        :class="{ 'opacity-0': !hiddenFlicker && Math.floor((currentTime / 1000) % 2) && (getDiffInfoRef.d > 0 || getDiffInfoRef.h > 0) }"
      >
        :
      </div>
    </template>
  </div>
</template>
